fix(layout-engine): render underlined tabs as one continuous line#3627
Merged
Conversation
…lay (SD-3330) Underlined tabs drew a border-bottom while adjacent text used native text-decoration, meeting at slightly different y and leaving a seam. One line-level overlay now owns the underline for both the inline and segment-positioned branches; native painters are suppressed where it covers the run. Scoped to single/double/dotted/dashed (words/wave/heavy and theme colors stay on the existing path). Tab paint-version now keys on fontSize/fontFamily/color/font epoch so a style change repaints. Covered by painter unit tests (inline + segment-positioned merged geometry), version-signature tests, overlay-scope guards, and a behavior test that types text+tabs, selects all, underlines, and asserts one continuous overlay.
…SD-3330) A tab-only paragraph has no text run, so the line fell back to synthetic 0.8/0.2 ascent/descent. Derive metrics from the tab's own font so a tab-only underlined line gets the same measured ascent/descent (underline offset, line height) as the equivalent text line. Effective only in a real browser; jsdom has no real font metrics, so validate via the layout/visual suites in CI.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d237d77db5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
tupizz
approved these changes
Jun 3, 2026
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
RTL paragraphs skip segment positioning and fall to inline flow so the browser places the bidi tabs, but the underline overlay built LTR left-offsets from the line start and suppressed the native underlines - painting on the wrong side. Gate the overlay on !isRtl so RTL keeps native text-decoration + tab borders; a mirrored RTL overlay is larger work and unnecessary here. Adds a painter regression test (RTL underlined-tab line -> no overlay, natives intact).
…nes (SD-3330) The inline-flow overlay builds left-origin offsets, so it mispainted - and suppressed the natively-correct underlines - on center/right-aligned, hanging/negative-indent, and atomic-run lines. Gate it to left/start-aligned LTR lines with a matching indent origin, built only from text/tab/line-break runs; the segment-positioned branch stays exempt (it captures spans at the same x it positions runs at). Add the tab's bold/italic to the version key (tab-only metrics depend on them via getFontInfoFromRun) and pin the overlay-top unit assertions to underlineOffsetFromLineTop. Tests: center/right alignment, hanging indent, and a boolean-underline field annotation.
… off (SD-3330) Sharpen the atomic-run regression: beyond checking no overlay is produced, assert the field annotation's own underline is not suppressed (textDecorationLine not forced to 'none'), via the aria-label selector.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #3611.
Draws one shared underline across text, spaces, and underlined tabs so the inline case and the tab-stop case stay continuous. Also expands the tab paint cache key and tightens tab-only line metrics to use the tab font.
Before:

After:
